package app

import (
	"github.com/fuxiaohei/hxgo"
	"net/http"
	"path"
	"github.com/Unknwon/com"
	"runtime"
	"runtime/debug"
)

/*
	App Handler
 */

// handler vars
var (
	// http handler
	Handler *hxgo.Handler
	// http route dispatcher
	Router *hxgo.Router
)

// return default static http handler
func defaultStaticHandler() hxgo.HandlerStaticFunc {
	return func(w http.ResponseWriter, r *http.Request) bool {
		// get static file path
		fUrl := path.Join(Root, r.URL.Path)
		if com.IsFile(fUrl) {
			http.ServeFile(w, r, fUrl)
			Log.Info("[" + Name + "] http static", r.Method, r.RequestURI)
			return true
		}
		return false
	}
}

// return default dynamic http handler
func defaultDynamicHandler() hxgo.HandlerDynamicFunc {
	return func(w http.ResponseWriter, r *http.Request) bool {
		// create request and response struct
		req := hxgo.NewRequested(r)
		res := hxgo.NewResponse(w)
		// set gzip
		res.IsGzip = Cfg.Bool("HttpGzip")
		// dispatch
		result := Router.Dispatch(res, req, View)
		if result == false {
			return false
		}
		// if response is not sent out, send response
		if !res.IsDone {
			res.Done()
		}
		// if http status >= 400, log as warning
		if res.Status >= 400 {
			Log.Warn("[" + Name + "] http", r.Method, r.RequestURI, res.Status)
			return true
		}
		Log.Info("[" + Name + "] http", r.Method, r.RequestURI, res.Status)
		return true
	}
}

// return default error handler
func defaultErrorHandler() hxgo.HandlerErrorFunc {
	return func(w http.ResponseWriter, r *http.Request, e hxgo.HandlerError) {
		// log http error
		Log.Warn("[" + Name + "] http", r.Method, r.RequestURI, e.Status)
		if e.Status >= 500 {
			// if http status >= 500, log error stack
			Log.Warn("[" + Name + "] trace", string(debug.Stack()))
		}
		// render error page
		body, err := View.Render("error.html", map[string]interface {}{
				"error":e,
				"request":r,
				"isDev":IsModeDev(),
				"isTest":IsModeTest(),
				"isPro":IsModePro(),
				"stack":string(debug.Stack()),
				"app":Name,
				"appVersion":Version,
				"goVersion":runtime.Version(),
				"hxgoVersion":hxgo.HXGO_VERSION,
			}, nil)
		// if something wrong in rendering error page, only show text error message
		if err != nil {
			http.Error(w, e.Err.Error(), e.Status)
			return
		}
		// write rendered error page
		w.Header().Add("Content-Type", "text/html;charset=UTF-8")
		w.WriteHeader(e.Status)
		w.Write([]byte(body))
	}
}

// init router and handler
func initHandler() {
	Router = hxgo.NewRouter()
	Handler, _ = hxgo.NewHandler(defaultStaticHandler(), defaultDynamicHandler(), defaultErrorHandler())
}

// add route map rule
func Map(url string, handler hxgo.RouteHandler) *hxgo.Route {
	r := hxgo.NewRoute(url, handler)
	Router.Append(r)
	Log.Warn("[" + Name + "]", "map " + url)
	return r
}
